#!/bin/sh -
# Copyright (c) 2019-2025, Sylabs Inc. All rights reserved.
# Copyright (c) 2015-2018, Yannick Cote <yhcote@gmail.com>. All rights reserved.
# Copyright (c) Contributors to the Apptainer project, established as
#   Apptainer a Series of LF Projects LLC.
# Use of this source code is governed by a BSD-style license that can be found
# in the LICENSE file.
set -e

verbose=0
profile=release

lang_c=1
lang_go=1

hstcc=
hstcc_opts="cc gcc clang i686-w64-mingw32-gcc x86_64-w64-mingw32-gcc"
hstcxx=
hstcxx_opts="c++ g++ clang++ i686-w64-mingw32-g++ x86_64-w64-mingw32-g++"
hstar=
hstld=
hstranlib=
hstobjcopy=
hstgo=
hstgo_version="1.24"
hstgo_opts="go"

tgtcc=
tgtcc_opts=$hstcc_opts
tgtcxx=
tgtcxx_opts=$hstcxx_opts
tgtar=
tgtld=
tgtranlib=
tgtobjcopy=

hststatic=0
tgtstatic=0

# user_cflags - user-defined CFLAGS without all the cflags_opts
user_cflags="$CFLAGS"
cflags_opts="-Wall -Werror -Wfatal-errors -Wno-unknown-warning-option \
-Wstrict-prototypes -Wpointer-arith -Wbad-function-cast \
-Woverlength-strings -Wframe-larger-than=2047 \
-Wno-sign-compare -Wclobbered -Wempty-body -Wmissing-parameter-type \
-Wtype-limits -Wunused-parameter -Wunused-but-set-parameter \
-Wno-discarded-qualifiers -Wno-incompatible-pointer-types \
-pipe -fmessage-length=0 -fPIC"
cflags="$CFLAGS -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -fstack-protector --param ssp-buffer-size=4"
ldflags=$LDFLAGS

package_name=singularity-ce
package_version=`scripts/get-version`

if test -z "${package_version}" ; then
	echo "Failed to get package version. Abort."
	exit 1
fi

with_network=1
with_squashfuse=1
with_suid=1
with_seccomp_check=1
with_libsubid_check=1

builddir=
prefix=
exec_prefix=
bindir=
sbindir=
libexecdir=
datarootdir=
datadir=
sysconfdir=
sharedstatedir=
localstatedir=
runstatedir=
includedir=
oldincludedir=
docdir=
infodir=
htmldir=
dvidir=
pdfdir=
psdir=
libdir=
localedir=
mandir=

reproducible=0

usage () {
	echo "${0##*/}: could not complete configuration"
}

usage_args () {
	echo "Usage: ${0##*/} [-vsS] [-P profile] [-b builddir] [-c hstcc] [-C tgtcc]"
	echo "                [-V version] [-x hstcxx] [-X tgtcxx]"
	echo "                [--INSTALLDIR=ARG (see below)]"
	echo
	echo "  Makeit general options:"
	echo "     -v   build project with verbose flags on"
	echo "     -s   build final host project binary statically"
	echo "     -S   build final target project binary statically"
	echo "     -P   use config profile to configure the project:"
	echo "            *release             normal release mode (production)"
	echo "             release-stripped    release mode, stripped symbols (rpm packaging)"
	echo "             debug               CGO objects built unoptimized, with symbols"
	echo "     -b   build project in \`builddir'"
	echo "     -c   build project with host C \`compiler'"
	echo "     -C   build project with target C\`compiler'"
	echo "     -V   build project with given version"
	echo "     -x   build project with host C++ \`compiler'"
	echo "     -X   build project with target C++ \`compiler'"
	echo "     -l   build project with source code language (-l C -l Go ...)"
	echo "     -h   this help"
	echo
	echo "  Singularity options:"
	echo "     --without-suid     do not install SUID binary (linux only)"
	echo "     --without-libsubid do not compile/install libsubid support (linux only)"
  echo "                        singularity will not honor nss subid configuration"
	echo "     --without-network  do not compile/install network plugins (linux only)"
	echo "     --without-seccomp  do not compile/install seccomp support (linux only)"
  echo
  echo "  Third-party dependencies:"
  echo "     --without-squashfuse  do not build squashfuse, use distro provided version"
	echo
	echo "  Path modification options:"
	echo "     --prefix         install project in \`prefix'"
	echo "     --exec-prefix    install project executables in \`exec-prefix'"
	echo "     --bindir         install user executables in \`bindir'"
	echo "     --sbindir        install admin executables in \`sbindir'"
	echo "     --libexecdir     install program executables in \`libexecdir'"
	echo "     --datarootdir    install read-only rootdir data in \`datarootdir'"
	echo "     --datadir        install read-only data in \`datadir'"
	echo "     --sysconfdir     install read-only config files in \`sysconfdir'"
	echo "     --sharedstatedir install writable data in \`sharedstatedir'"
	echo "     --localstatedir  install writable config files in \`localstatedir'"
	echo "     --runstatedir    install writable per-process data in \`runstatedir'"
	echo "     --includedir     install header files in \`includedir'"
	echo "     --oldincludedir  install system header files in \`oldincludedir'"
	echo "     --docdir         install root documentation in \`docdir'"
	echo "     --infodir        install info documentation in \`infodir'"
	echo "     --htmldir        install html documentation in \`htmldir'"
	echo "     --dvidir         install dvi documentation in \`dvidir'"
	echo "     --pdfdir         install pdf documentation in \`pdfdir'"
	echo "     --psdir          install ps documentation in \`psdir'"
	echo "     --libdir         install libraries in \`libdir'"
	echo "     --localedir      install locale dependent data in \`localedir'"
	echo "     --mandir         install man documentation in \`mandir'"
  echo
  echo "  Reproducible builds:"
  echo "     --reproducible   set reproducible SOURCEDIR & BUILDDIR values in binaries."
  echo "                      This will disable plugin build functionality."

	echo
}

# save the command line
cmdline="`pwd -P`/${0##*/} $*"

while [ $# -ne 0 ]; do
 case $1 in
  -p|--prefix*)
   if [ "$1" = "-p" ]; then
    if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
    fi
    prefix=$2
    shift
   else
    if echo "$1" | awk '/^--prefix=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
    fi
    prefix=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   fi
   shift;;
  -e|--exec-prefix*)
   if [ "$1" = "-e" ]; then
    if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
    fi
    exec_prefix=$2
    shift
   else
    if echo "$1" | awk '/^--exec-prefix=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
    fi
    exec_prefix=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   fi
   shift;;
  --bindir*)
   if echo "$1" | awk '/^--bindir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   bindir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --sbindir*)
   if echo "$1" | awk '/^--sbindir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   sbindir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --libexecdir*)
   if echo "$1" | awk '/^--libexecdir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   libexecdir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --datarootdir*)
   if echo "$1" | awk '/^--datarootdir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   datarootdir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --datadir*)
   if echo "$1" | awk '/^--datadir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   datadir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --sysconfdir*)
   if echo "$1" | awk '/^--sysconfdir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   sysconfdir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --sharedstatedir*)
   if echo "$1" | awk '/^--sharedstatedir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   sharedstatedir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --localstatedir*)
   if echo "$1" | awk '/^--localstatedir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   localstatedir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --runstatedir*)
   if echo "$1" | awk '/^--runstatedir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   runstatedir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --includedir*)
   if echo "$1" | awk '/^--includedir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   includedir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --oldincludedir*)
   if echo "$1" | awk '/^--oldincludedir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   oldincludedir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --docdir*)
   if echo "$1" | awk '/^--docdir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   docdir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --infodir*)
   if echo "$1" | awk '/^--infodir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   infodir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --htmldir*)
   if echo "$1" | awk '/^--htmldir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   htmldir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --dvidir*)
   if echo "$1" | awk '/^--dvidir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   dvidir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --pdfdir*)
   if echo "$1" | awk '/^--pdfdir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   pdfdir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --psdir*)
   if echo "$1" | awk '/^--psdir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   psdir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --libdir*)
   if echo "$1" | awk '/^--libdir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   libdir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --localedir*)
   if echo "$1" | awk '/^--localedir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   localedir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  --mandir*)
   if echo "$1" | awk '/^--mandir=.+$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   mandir=`echo $1 | sed -e 's|.*\=\(.*\)|\1|'`
   shift;;
  -P)
   if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   profile=$2; shift; shift;;
  -b)
   if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   builddir="$2"; shift; shift;;
  -c)
   if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   hstcc="$2"; shift; shift;;
  -C)
   if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   tgtcc="$2"; shift; shift;;
  -x)
   if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   hstcxx="$2"; shift; shift;;
  -X)
   if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   tgtcxx="$2"; shift; shift;;
  -s)
   hststatic=1; shift;;
  -S)
   tgtstatic=1; shift;;
  -v)
   verbose=1; shift;;
  --without-suid)
   with_suid=0; shift;;
  --without-libsubid)
   with_libsubid_check=0; shift;;
  --without-network)
   with_network=0; shift;;
  --without-seccomp)
   with_seccomp_check=0; shift;;
  --without-squashfuse)
   with_squashfuse=0; shift;;
  --reproducible)
   reproducible=1; shift;;
  -V)
   if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   package_version="$2"; shift; shift;;
  -l)
   if ! echo "$2" | awk '/^-.*/ || /^$/ { exit 2 }'; then
     echo "error: option requires an argument: $1"
     exit
   fi
   case "$2" in
    c|C) lang_c=1;;
    go|GO|Go|Golang) lang_go=1;;
    *) echo "error: language not supported: $2"
       exit;;
   esac
   shift; shift;;
  -h) usage_args; exit 2;;
  --) shift; break;;
  ?) usage_args
     exit 2;;
  *) break;;
 esac
done

# use a colon to provide additional version information such as a
# release number.
short_version="`echo "$package_version"|sed 's/:.*//'`"
release_info="`echo "$package_version"|sed 's/^[^:]*://'`"
if [ "${short_version}" = "${release_info}" ]; then
	# $package_version has no colon
	release_info=1
fi

# non-option param
if [ $# != 0 ]; then
	usage_args
	exit 2
fi

# defaults paths
if [ -z "${prefix}" ]; then
	prefix=/usr/local
fi
if [ -z "${exec_prefix}" ]; then
	exec_prefix=${prefix}
fi
if [ -z "${bindir}" ]; then
	bindir=${exec_prefix}/bin
fi
if [ -z "${sbindir}" ]; then
	sbindir=${exec_prefix}/sbin
fi
if [ -z "${libexecdir}" ]; then
	libexecdir=${exec_prefix}/libexec
fi
if [ -z "${datarootdir}" ]; then
	datarootdir=${prefix}/share
fi
if [ -z "${datadir}" ]; then
	datadir=${datarootdir}
fi
if [ -z "${sysconfdir}" ]; then
	sysconfdir=${prefix}/etc
fi
if [ -z "${sharedstatedir}" ]; then
	sharedstatedir=${prefix}/com
fi
if [ -z "${localstatedir}" ]; then
	localstatedir=${prefix}/var
fi
if [ -z "${runstatedir}" ]; then
	runstatedir=${localstatedir}/run
fi
if [ -z "${includedir}" ]; then
	includedir=${prefix}/include
fi
if [ -z "${oldincludedir}" ]; then
	oldincludedir=/usr/include
fi
if [ -z "${docdir}" ]; then
	docdir=${datarootdir}/doc/${package_name}
fi
if [ -z "${infodir}" ]; then
	infodir=${datarootdir}/info
fi
if [ -z "${htmldir}" ]; then
	htmldir=${docdir}
fi
if [ -z "${dvidir}" ]; then
	dvidir=${docdir}
fi
if [ -z "${pdfdir}" ]; then
	pdfdir=${docdir}
fi
if [ -z "${psdir}" ]; then
	psdir=${docdir}
fi
if [ -z "${libdir}" ]; then
	libdir=${exec_prefix}/lib
fi
if [ -z "${localedir}" ]; then
	localedir=${datarootdir}/locale
fi
if [ -z "${mandir}" ]; then
	mandir=${datarootdir}/man
fi

# check that at least a language is selected
if [ $lang_c -eq 0 -a $lang_go -eq 0 ]; then
	echo "error: no project source code language selected"
	echo "NOTE: use ${0##*/} with the [-l (C,Go,...) option]"
	exit 2
fi

# config profile validation
case $profile in
	release);;
	release-stripped);;
	debug);;
	*) echo "$profile: no such config profile"
	   echo "       -P use config profile to configure the project:"
	   echo "           release             (DEFAULT) normal release mode (production)"
	   echo "           release-stripped    release mode, stripped symbols (rpm packaging)"
	   echo "           debug               C portion of CGO built unoptimized, with symbols"
	   exit 2;;
esac

# sourcedir and builddir
sourcedir=`pwd -P`
if [ "$builddir" = "" ]; then
	builddir=$sourcedir/builddir
else
	mkdir -p $builddir
	if ! builddir=`(cd $builddir 2>/dev/null && pwd -P)`; then
		echo "error: could not chdir to $builddir"
		exit 2
	fi
fi
if [ -e $builddir -a $builddir != "." -a $builddir != ".." ]; then
	rm -rf $builddir
fi

# setup some makeit base directories
makeit_dir=$sourcedir/makeit
makeit_mconflist=$sourcedir/mlocal/mconflist
makeit_fragsdir=$sourcedir/mlocal/frags
makeit_checksdir=$sourcedir/mlocal/checks
makeit_scriptsdir=$sourcedir/mlocal/scripts
# mconfig tmpfiles path
makeit_interdir=$builddir/makeit-intermediate
makeit_testprogdir=$makeit_interdir/testprogs
# final generated Makefile
makeit_makefile=$builddir/Makefile
makeit_makefile_base=$makeit_interdir/base.mk

# work directory and file creation
mkdir -p $builddir
mkdir -p $makeit_interdir
mkdir -p $makeit_testprogdir
:>$makeit_makefile_base


# load mconfig helper scripts
. $makeit_scriptsdir/config_h.sh #functions to add entries in config.h (C projects)


printf "Configuring for project \`$package_name' with languages: "
if [ $lang_c -eq 1 ]; then
	printf "C"
fi
if [ $lang_go -eq 1 ]; then
	printf ", Golang"
fi
echo

#######################################################################
# mlocal/checks/project-pre.chk -- executes before standard base checks
#######################################################################
if [ -f $makeit_checksdir/project-pre.chk ]; then
	echo "=> running pre-basechecks project specific checks ..."
	. $makeit_checksdir/project-pre.chk
fi


#######################################################################
# mlocal/checks/basechecks.chk -- common to most projects
#######################################################################
if [ -f $makeit_checksdir/basechecks.chk ]; then
	echo "=> running base system checks ..."
	. $makeit_checksdir/basechecks.chk
else
	echo "error: file $makeit_checksdir/basechecks.chk needs to be present"
	exit 2
fi


#######################################################################
# mlocal/checks/project-post.chk -- executes after standard base checks
#######################################################################
if [ -f $makeit_checksdir/project-post.chk ]; then
	echo "=> running post-basechecks project specific checks ..."
	. $makeit_checksdir/project-post.chk
fi


#######################################################################
# Generated fragments
#######################################################################
echo "=> generating fragments ..."
if [ ! -d $makeit_fragsdir ]; then
	echo "error: $makeit_fragsdir should be populated with Makefile fragments."
	echo "NOTE: Fragments may be copied from examples or existing projects"
	echo "NOTE: to $sourcedir/mlocal/* and tweak for your project."
	exit 2
fi


########################
# verbosity
########################
if [ "$verbose" = 1 ]; then
	echo "# build with verbose flag on" >> $makeit_makefile_base
	echo "V :=" >> $makeit_makefile_base
else
	echo "# silent build" >> $makeit_makefile_base
	echo "V := @" >> $makeit_makefile_base
fi
echo >> $makeit_makefile_base

# disable those options for non unix system
if [ "$host" != "unix" ]; then
	with_network=0
	with_suid=0
fi

########################
# build tools
########################
cat >> $makeit_makefile_base << EOF
# source/build locations
BUILDDIR := .
BUILDDIR_ABSPATH := $builddir
SOURCEDIR := $sourcedir
SCRIPTSDIR := $makeit_scriptsdir
CONTRIBDIR := $contribdir
PREFIX := $prefix
EXECPREFIX := $exec_prefix
BINDIR := $bindir
SBINDIR := $sbindir
LIBEXECDIR := $libexecdir
DATAROOTDIR := $datarootdir
DATADIR := $datadir
SYSCONFDIR := $sysconfdir
SHAREDSTATEDIR := $sharedstatedir
LOCALSTATEDIR := $localstatedir
RUNSTATEDIR := $runstatedir
INCLUDEDIR := $includedir
OLDINCLUDEDIR := $oldincludedir
DOCDIR := $docdir
INFODIR := $infodir
HTMLDIR := $htmldir
DVIDIR := $dvidir
PDFDIR := $pdfdir
PSDIR := $psdir
LIBDIR := $libdir
LOCALEDIR := $localedir
MANDIR := $mandir
RPMPREFIX:=

NAME := $package_name
SHORT_VERSION := $short_version
VERSION := $package_version

HOSTAR := $hstar
HOSTCC := $hstcc
HOSTCXX := $hstcxx
HOSTLD := $hstcc
HOSTRANLIB := $hstranlib
HOSTSIZE := size
HOSTOBJCOPY := $hstobjcopy

AR := $tgtar
CC := $tgtcc
CXX := $tgtcxx
LD := $tgtld
RANLIB := $tgtranlib
SIZE := size
OBJCOPY := $tgtobjcopy

ARCH := $tgt_arch

CFLAGS := $cflags

GO := $hstgo

CGO_CFLAGS := -I$builddir $CGO_CFLAGS
CGO_LDFLAGS := $CGO_LDFLAGS
CGO_CPPFLAGS := $CGO_CPPFLAGS
CGO_CXXFLAGS := $CGO_CXXFLAGS
export CGO_CFLAGS CGO_LDFLAGS CGO_CPPFLAGS CGO_CXXFLAGS
EOF


########################
# modules
########################
:>$makeit_interdir/module.lst

found_modules=`(cat $makeit_mconflist | awk '{ printf("%s ", $0) }') 2>/dev/null || true`
if [ "$found_modules" = "" ]; then
	found_modules=`find . -name '*.mconf' -print`
fi

if [ "$found_modules" != "" ]; then
	echo " found build modules:"
	echo "CPPFLAGS :=" >> $makeit_makefile_base
	# NOTE: parsed module (*.mconf) files only substitute var tgt_arch for now
	for m in $found_modules; do
		mod=`eval echo ${m##*./}`
		modpath=`eval echo ${mod%/*}`
		if [ ! -f $mod ]; then
			echo "error: module file \`$mod' not found!"
			exit 2
		fi
		if [ $mod = $modpath ]; then
			modpath="."
		fi

		echo "   +-> $mod"
		echo "$modpath `eval basename $mod`" >> $makeit_interdir/module.lst
		mkdir -p $makeit_interdir/$modpath
		cat $mod | awk -v tgt_arch=$tgt_arch '{ gsub(/tgt_arch/, tgt_arch); print }' > \
			$makeit_interdir/${mod}.parsed
	done
	echo >> $makeit_makefile_base
fi

# init LDFLAGS if static builds are supported
if [ "$hststatic" = "1" -a "$tgtstatic" = "1" ]; then
	echo "LDFLAGS := -static $ldflags" >> $makeit_makefile_base
else
	echo "LDFLAGS := $ldflags" >> $makeit_makefile_base
fi
echo >> $makeit_makefile_base

cat >> $makeit_makefile_base << EOF
# make sure \`all' is the first rule
all:
EOF


# call genmod.awk, generating Makefile components
$makeit_dir/genmod.awk mconflist=$makeit_interdir/module.lst \
	host=$host \
	makeitgendir=$makeit_interdir \
	tmpldir=$makeit_dir/tmpl



#######################################################################
# Target Makefile
#######################################################################
drawline () {
	echo >> $makeit_makefile
	printf "# [ Embedding file : %50s ] #\n" $1 >> $makeit_makefile
	echo >> $makeit_makefile
}

echo "=> building Makefile ..."

:> $makeit_makefile
echo "#" >> $makeit_makefile
echo "# Non-recursive Makefile GENERATED by \`${0##*/}' -- `date`" >> $makeit_makefile
echo "# configured: $cmdline" >> $makeit_makefile
echo "#" >> $makeit_makefile

drawline $makeit_makefile_base
cat $makeit_makefile_base >> $makeit_makefile

drawline $makeit_fragsdir/common_opts.mk
cat $makeit_fragsdir/common_opts.mk >> $makeit_makefile

drawline $makeit_fragsdir/go_common_opts.mk
cat $makeit_fragsdir/go_common_opts.mk >> $makeit_makefile

if [ -f "$makeit_fragsdir/go_${host}_opts.mk" ]; then
	drawline $makeit_fragsdir/go_${host}_opts.mk
	cat $makeit_fragsdir/go_${host}_opts.mk >> $makeit_makefile
fi

if [ "$appsec" = "1" ]; then
	drawline $makeit_fragsdir/go_appsec_opts.mk
	cat $makeit_fragsdir/go_appsec_opts.mk >> $makeit_makefile
fi

if [ "$libsubid" = "1" ]; then
	drawline $makeit_fragsdir/go_libsubid_opts.mk
	cat $makeit_fragsdir/go_libsubid_opts.mk >> $makeit_makefile
fi

if [ "$build_runtime" = "1" ]; then
	drawline $makeit_fragsdir/go_runtime_opts.mk
	cat $makeit_fragsdir/go_runtime_opts.mk >> $makeit_makefile
fi


case $profile in
	release)
		if [ $lang_c -eq 1 ]; then
			drawline $makeit_fragsdir/release_opts.mk
			cat $makeit_fragsdir/release_opts.mk >> $makeit_makefile
		fi
		if [ $lang_go -eq 1 ]; then
			drawline $makeit_fragsdir/go_normal_opts.mk
			cat $makeit_fragsdir/go_normal_opts.mk >> $makeit_makefile
		fi
		;;
	release-stripped)
		if [ $lang_c -eq 1 ]; then
			drawline $makeit_fragsdir/release_opts.mk
			cat $makeit_fragsdir/release_opts.mk >> $makeit_makefile
		fi
		if [ $lang_go -eq 1 ]; then
			drawline $makeit_fragsdir/go_stripped_opts.mk
			cat $makeit_fragsdir/go_stripped_opts.mk >> $makeit_makefile
		fi
		;;
	debug)
		if [ $lang_c -eq 1 ]; then
			drawline $makeit_fragsdir/debug_opts.mk
			cat $makeit_fragsdir/debug_opts.mk >> $makeit_makefile
		fi
		if [ $lang_go -eq 1 ]; then
			drawline $makeit_fragsdir/go_normal_opts.mk
			cat $makeit_fragsdir/go_normal_opts.mk >> $makeit_makefile
		fi
		;;
esac

if [ -f "$makeit_fragsdir/arch_${tgt_arch}_opts.mk" ]; then
	drawline $makeit_fragsdir/arch_${tgt_arch}_opts.mk
	cat $makeit_fragsdir/arch_${tgt_arch}_opts.mk >> $makeit_makefile
fi

drawline $makeit_interdir/combined-mconfsready.mk
cat $makeit_interdir/combined-mconfsready.mk >> $makeit_makefile

drawline $makeit_interdir/all.mk
cat $makeit_interdir/all.mk >> $makeit_makefile

drawline $makeit_fragsdir/build_cli.mk
cat $makeit_fragsdir/build_cli.mk >> $makeit_makefile

if [ "$with_network" = 1 ]; then
    drawline $makeit_fragsdir/build_network.mk
    cat $makeit_fragsdir/build_network.mk >> $makeit_makefile
fi

if [ "$with_squashfuse" = 1 ]; then
    drawline $makeit_fragsdir/build_squashfuse.mk
    cat $makeit_fragsdir/build_squashfuse.mk >> $makeit_makefile
fi

if [ "$build_runtime" = 1 ]; then
	drawline $makeit_fragsdir/build_runtime.mk
	cat $makeit_fragsdir/build_runtime.mk >> $makeit_makefile
fi

if [ "$with_suid" = 1 ]; then
	drawline $makeit_fragsdir/build_runtime_suid.mk
	cat $makeit_fragsdir/build_runtime_suid.mk >> $makeit_makefile
fi

drawline $makeit_fragsdir/build_scripts.mk
cat $makeit_fragsdir/build_scripts.mk >> $makeit_makefile

drawline $makeit_fragsdir/build_singularity-buildkitd.mk
cat $makeit_fragsdir/build_singularity-buildkitd.mk >> $makeit_makefile

drawline $makeit_fragsdir/Makefile.stub
# here, `depends' need to happen after all other rules; at the very end
final_all=`cat $makeit_interdir/all.mk | awk 'BEGIN { FS="all: " } { print $2 }'`
cat $makeit_fragsdir/Makefile.stub | awk \
	"{ gsub(/^collect:/, \"collect: $final_all\"); print }" >> $makeit_makefile



#######################################################################
# Rpm spec for project package
#######################################################################

if [ "$host" = "unix" ]; then
	RPMSPEC=singularity-ce.spec
	echo "=> generating $RPMSPEC ..."
	rm -f $sourcedir/$RPMSPEC

	# Transform version numbers so that rpm accepts them:
	#
	# 3.4.2-rc.1            ->  3.4.2~rc.1
	# 3.4.2                 ->  3.4.2
	# 3.4.2+522-gee98ef356  ->  3.4.2+522.gee98ef356
	package_rpm_version="$(echo "${short_version}" | sed -e 's,\(^[^+]\+\)-,\1~,; s,-,.,g')"

	sed "s/@PACKAGE_VERSION@/${package_version}/;s/@PACKAGE_RPM_VERSION@/${package_rpm_version}/;s/@PACKAGE_RELEASE@/${release_info}/" \
		$sourcedir/dist/rpm/$RPMSPEC.in >$sourcedir/$RPMSPEC
fi





#######################################################################
# Configuration results
#######################################################################
echo "=> project $package_name setup with :"
echo "    - host arch: $hst_arch"
echo "    - host wordsize: ${hst_word}-bit"
echo "    - host C compiler: $hstcc"
if test "${lang_go}" -eq 1 ; then
	echo "    - host Go compiler: $hstgo"
fi
echo "    - host system: $host"
echo "      ---"
echo "    - target arch: $tgt_arch"
echo "    - target wordsize: ${tgt_word}-bit"
echo "    - target C compiler: $tgtcc"
echo "      ---"
echo "    - config profile: $profile"
echo "      ---"
if [ "$with_suid" = 0 ]; then
	echo "    - SUID install: no"
else
	echo "    - SUID install: yes"
fi
if [ "$with_network" = 0 ]; then
	echo "    - Network plugins: no"
else
	echo "    - Network plugins: yes"
fi
if [ "$appsec" = 0 ]; then
	echo "    - seccomp support: no"
else
	echo "    - seccomp support: yes"
fi
if [ "$libsubid" = 0 ]; then
	echo "    - libsubid support: no"
else
	echo "    - libsubid support: yes"
fi
if [ "$with_squashfuse" = 0 ]; then
	echo "    - Build squashfuse: no"
else
	echo "    - Build squashfuse: yes"
fi
echo "      ---"
if [ "$verbose" = 1 ]; then
	echo "    - verbose: yes"
else
	echo "    - verbose: no"
fi
if test "${host}" = "unix" ; then
	echo "      ---"
	echo "    - cryptsetup: ${cryptsetup_path}"
fi
echo "      ---"
echo "    - version: $package_version"

echo "=> $builddir/Makefile ready, try:"
echo "   $ cd $builddir"
echo "   $ make"
